Arduino Serial使用以及各种读写函数区别 您所在的位置:网站首页 write和write down的区别 Arduino Serial使用以及各种读写函数区别

Arduino Serial使用以及各种读写函数区别

2023-11-05 07:23| 来源: 网络整理| 查看: 265

Arduino Serial使用以及各种读写函数区别

之前有一篇文章总结了Python的串口使用,自认为已经深得要领。直到最近开始研究Arduino,用的串口传输数据,心里还是有很多问题,时常在运用相关函数的时候想起之前Python上的串口知识点,两者有着千丝万缕的关系。从头开始理一下思路,原理都是一样的,计算机只懂得二进制,而人类懂得ASCII文本,如何理解两者之间架起的这座桥梁甚是关键….

1. 前言

常见的串口调试是将Arduino与PC相连,然后利用PC上的串口助手与其通信调试,但是有一个注意点是,调试Arduino串口时,用串口助手调试与跟程序语言(比如Python,Arduino语言)调试的传输的数据有区别,比如串口助手输入框中输入97时你可能输入的是两个字符9与7,而在用Arduino语法(Serial.write(97))写的时候就是代表ASCII的a,或者在Python中是ser.write(b'a')也可写成ser.write([97])),两者调试方法有明显的差别性。

2. 两个重要的写函数(write,print)2.1 Serial.write()

串口中通信的一定是byte(字节),也就是八位Bit(二进制位),可以为一个字节,也可为多个字节;如果想发送代表数字的字符,应该使用print()函数(这个后面说);该函数返回有几个字节被发送了。

Serial.write()一共有三种语法

Serial.write(val)

发送单个字节,比如发送97,那么等于发送十进制ASCII码值为97的字符,也就是字母a

Serial.write(str)

发送字符串作为一系列的字节,比如int bytesSent = Serial.write(“hello”);

注意,这里发送字符串一定要用双引号,我一开始习惯了Python的用法,单双引号看心情来用,直接只收到一个字节,问题很大

Serial.write(buf, len)

发送一个长度为len的数组(一般为char类型数组),跟上面Serial.write(str)作用是一致的,只是传入参数不一样

2.2 Serial.print()

Prints data to the serial port as human-readable ASCII text.

println与print类似,只是多了换行符,这里只介绍print函数。上面这行英文已经把它跟read()函数的关系分的很清楚了。这个命令可以有多种形式。每个数字都使用ASCII字符打印。浮点数类似地打印为ASCII数字,默认为两位小数。字节作为单个字符发送。字符和字符串按原样发送。例如:

12345678Serial.print(78) gives "78"

Serial.print(1.23456) gives "1.23"

Serial.print('N') gives "N"

Serial.print("Hello world.") gives "Hello world."

还有第二个可选参数format是具体的格式,允许二进制八进制十六进制等,例如:

12345678910111213Serial.print(78, BIN) gives "1001110"

Serial.print(78, OCT) gives "116"

Serial.print(78, DEC) gives "78"

Serial.print(78, HEX) gives "4E"

Serial.print(1.23456, 0) gives "1"

Serial.print(1.23456, 2) gives "1.23"

Serial.print(1.23456, 4) gives "1.2346"

2.3 Serial.write与Serial.print函数的区别

谢邀,我觉得print,printf是开发出来专门针对pc端显示的,write则是用来与串口设备通信的,当然在老手眼里怎么用都行 ——————from逼乎某大佬回答

按照arduino官网reference的解释,Serial. print()是print data to the serial port as human-reading ASC II text ,Serial. write()是write binary data to the serial port ,一个转化为文本输出,一个是数据输出。

我在测试的时候刚开始并没有发现两者的区别。起初我认为传数据就该用Serial.write,而对于Serial.print这是在用串口助手的时候用,打印一些格式啥的,好利于调试辨认啥的等等(事实确实如此,但不仅于此)

于是我就将这两者的区别与Python中sys.stdout.write与内置的print函数作比较,前者不会写换行符然后是写到缓冲区,而print函数每次都有换行符,清空了缓冲区,然后就打印到屏幕上了,而且print函数自带了很多格式,可以跟format函数配合啥的,倒是跟Arduino的print有几分相似……但是其实这并不是重点~

我认为Arduino中的write与print还是存在缓冲区这个区别的,比如是在write中设置了timeout等操作,达到了与print类似的操作,这里只是猜测下,不做深究

重点来了!

我在这里Arduino 的 Serial.write() 和 Serial.print() 的区别在哪里?看到了答案?

在输出字符或字符串时,没有任何区别 在输出数值时,write会直接输出数据本身,而print会将其转化为可显示的ASCII字符(其实我觉得不妥,转换是串口助手来转换的,应该是算是说转换成可以传输的ASCII码值)

当时我的想法跟amazing814答主一样,而跟最高赞同者那位相反,后来发现我们概念理解错了他“错误”的回答如下:

1, print 出来的是真实数值, 2, write出来的是ascii码表对应的值(或者是说”对应的图形”)

错在了串口助手会自动将数据转换程ASCII文本! 反正,你要知道的是,串口发送或者读取到的数据都是字节!这一点用Python串口模块自己尝试一下就行!

所以Serial.write与Serial.print最大的区别就是传进函数中的数据,前者是真正的原始数据(int型或者说二进制位的数值),得到的是数据本身,而使用print函数的时候会以多个字节的形式向串口传递括号中数值,会将它看成一个字符串,传递其中每一个字符的ASCII码。例如你举的例子“78”会向串口传递“7”和“8”的ASCII码的值。

比如 Serial.write(78) ,发送的是N(换算成二进制就是01001110),得到的也是N的字节(即二进制位),虽然串口助手上显示的是N与Serial.print(78),发送的7和8两个字节,内部先把7,8转换成55,56的原始数据,在发送出去,得到也是55,56

所以那位错误的答主,想说的其实并不是“真实”,而是“相同”! 真正的计算机数据是二进制位(为了方便,转换成十进制了,也就是上面的55,56)

print主要用于”给人看”的地方. 电脑内部通讯, 如果程序内不需要用人眼再检查, 用 write 会比较好, 直接快捷.

3. Serial.read 相关函数3.1 Serial.read()

读取即将来的串口数据,但是只读取第一个字节,且这个字节的数据类型为int,即ASCII码值。

通常与Serial.available()一起用,例子如下:

1234567891011121314151617int incomingByte = 0; // for incoming serial data

void setup() { Serial.begin(9600); // opens serial port, sets data rate to 9600 bps}

void loop() { // send data only when you receive data: if (Serial.available() > 0) { // read the incoming byte: incomingByte = Serial.read();

// say what you got: Serial.print("I received: "); Serial.println(incomingByte, DEC); }}

串口发送数据与读到数据都为字节,所以该函数return回来int 型数据很正常,但是我们可以直接拿来跟字符比较或者用到某些话函数中,这得益于在C语言中单引号括起一个字符实际上代表一个整数,即ASCII码值

,从Arduino内置的例子就能看到:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970void setup() { // Open serial communications and wait for port to open: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only }

// send an intro: Serial.println("send any byte and I'll tell you everything I can about it"); Serial.println();}

void loop() { // get any incoming bytes: if (Serial.available() > 0) { int thisChar = Serial.read();

// say what was sent: Serial.print("You sent me: \'"); Serial.write(thisChar); Serial.print("\' ASCII Value: "); Serial.println(thisChar);

// analyze what was sent: if (isAlphaNumeric(thisChar)) { Serial.println("it's alphanumeric"); } if (isAlpha(thisChar)) { Serial.println("it's alphabetic"); } if (isAscii(thisChar)) { Serial.println("it's ASCII"); } if (isWhitespace(thisChar)) { Serial.println("it's whitespace"); } if (isControl(thisChar)) { Serial.println("it's a control character"); } if (isDigit(thisChar)) { Serial.println("it's a numeric digit"); } if (isGraph(thisChar)) { Serial.println("it's a printable character that's not whitespace"); } if (isLowerCase(thisChar)) { Serial.println("it's lower case"); } if (isPrintable(thisChar)) { Serial.println("it's printable"); } if (isPunct(thisChar)) { Serial.println("it's punctuation"); } if (isSpace(thisChar)) { Serial.println("it's a space character"); } if (isUpperCase(thisChar)) { Serial.println("it's upper case"); } if (isHexadecimalDigit(thisChar)) { Serial.println("it's a valid hexadecimaldigit (i.e. 0 - 9, a - F, or A - F)"); }

// add some space and ask for another byte: Serial.println(); Serial.println("Give me another byte:"); Serial.println(); }}

3.2 Serial.readBytes(buffer, length)

Serial.readBytes从串行端口读取字符到缓冲区,返回放入缓冲区的字节数,如果超时该函数将中断

这个函数我看到的用法是放在字符数组中,然后再利用数组的特性进行一些操作,例子如下:

1234567891011121314char mystr[10]; //Initialized variable to store recieved data

void setup() { // Begin the Serial at 9600 Baud Serial.begin(9600);}

void loop() { Serial.readBytes(mystr,5); //Read the serial data and store in var Serial.println(mystr); //Print data on Serial Monitor for (byte i = 0; i < 5; i = i + 1) { Serial.println(mystr[i]); delay(1000);}

3.3 Serial.readString()

Serial.readString将串行缓冲区中的字符读入String,如果超时该函数将中断

123456789101112String a;

void setup() {Serial.begin(9600); // opens serial port, sets data rate to 9600 bps}void loop() {

while(Serial.available()) { a= Serial.readString();// read the incoming data as string Serial.println(a);}}

当时这个函数与上面的搞不太清楚,所以试了下。其实这个函数是读取发送过来的字符串,存到一个String类型的变量里,用来打印,或者处理(Serial.write()无法字节发送String类型的变量)再发出去等等,可以看一下String类型的变量很多个方法比如toCharArray(),toInt()之类的

4. 总结

经历了两天的疑惑解惑过程,发现自己关于串口的基本功还是不够扎实,这个过程中需要自己不断反复地尝试与验证,剥开代码语言的皮囊,看到更下面真实的骨架,其实也挺开心的,故再花点时间整理在这里留作总结以及反思!

Arduino Serial

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

用Python在树莓派中使用MCP23017 I/O扩展模块 上一篇 Python中关于键盘行为的方法总结 下一篇


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有